<template>
  <div class="main">
    <div class="input-area" v-show="page.asideIndex == '1'">
      <div class="menu">
        <el-menu
          mode="horizontal"
          @select="tabChange"
          default-active="1"
          :ellipsis="false"
        >
          <el-menu-item index="1">选择视频</el-menu-item>
        </el-menu>
      </div>
      <el-upload
        class="upload-demo"
        action="#"
        :auto-upload="false"
        :showFileList="false"
        multiple
        @change="fileChange"
      >
        <el-button type="primary" class="up-btn">点击上传</el-button>
      </el-upload>
      <div v-for="(item, index) in fileList" :key="item.uid" class="video-list">
        <div style="display: flex; gap: 16px; width: 90%">
          <video
            :src="item.raw?.path"
            controls
            class="video"
            :id="item.uid.toString()"
          ></video>
          <div class="mid-content">
            <div class="content">
              <div class="row">{{ getFileName(item.name) }}</div>
              <div class="row">
                <span
                  ><el-icon><document /></el-icon>
                  {{ getExtension(item.name) }}</span
                >
                <span>
                  <el-icon><crop /></el-icon>{{ item.width }} *
                  {{ item.height }}</span
                >
              </div>
              <div class="row">
                <span
                  ><el-icon><coin /></el-icon
                  >{{ ((item?.size || 0) / 1048576 || 0).toFixed(2) }}MB</span
                >
                <span
                  ><el-icon><odometer /></el-icon>{{ item.duration }}</span
                >
              </div>
            </div>
            <div>
              <span>
                <el-icon><crop /></el-icon>{{ item.width }} *
                {{ item.height }}</span
              >
              <div>
                <span>h264</span>
              </div>
            </div>
          </div>
        </div>
        <div class="trans-box">
          <el-button
            type="primary"
            class="trans-btn"
            @click="toConvert(item)"
            >{{ item.btnTitle }}</el-button
          >
          <el-button
            type="primary"
            class="trans-btn"
            @click="showDialogVisible(item)"
            >{{ item.btnTitleTwo }}</el-button
          >
        </div>
        <el-icon class="delete-icon" @click="deleteItem(index)"
          ><delete
        /></el-icon>
      </div>
    </div>
    <el-dialog
      title="填写剪切开始结束时间（s）"
      v-model="dialogVisible"
      width="30%"
    >
      <el-form-item label="开始时间">
        <el-input v-model="startTime" type="number"></el-input>
      </el-form-item>
      <el-form-item label="结束时间">
        <el-input v-model="endTime" type="number"></el-input>
      </el-form-item>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="toCut">确 定</el-button>
      </span>
    </el-dialog>
    <Temps v-if="page.asideIndex == '4'"></Temps>
    <div class="main-config-page" v-if="page.asideIndex == '3'">
      <ConfigPage></ConfigPage>
    </div>
  </div>
</template>

<script setup lang="ts">
import ConfigPage from "../configpage/ConfigPage.vue";
import Temps from "../temps/Temps.vue";
import { ElMessage } from "element-plus";
import { nextTick, ref } from "vue";
import { useTtsStore } from "@/store/store";
import { storeToRefs } from "pinia";

const path = require("path");
const exec = require("child_process").exec;
// 定义上传文件类型
interface CustomUploadFile {
  btnTitle?: string;
  btnTitleTwo?: string;
  width?: number;
  height?: number;
  duration?: string;
  time?: number;
  name: string;
  percentage?: number;
  size?: number;
  response?: unknown;
  uid: number;
  url?: string;
  raw?: {
    path: string | undefined;
    uid: number;
  };
}
// 定义视频元数据返回类型
interface VideoMetadata {
  width: number;
  height: number;
  duration: number;
}
const fileList = ref<CustomUploadFile[]>([]);
const currentItem = ref<CustomUploadFile>();
const dialogVisible = ref<boolean>(false);
const startTime = ref<number>(0);
const endTime = ref<number | undefined>(0);

const store = useTtsStore();
const { page } = storeToRefs(store);

const tabChange = (index: number) => {
  page.value.tabIndex = index.toString();
};

const fileChange = (files: CustomUploadFile, list: CustomUploadFile[]) => {
  fileList.value = list;
  fileList.value.forEach(async (element) => {
    const obj = await getVideoInfo(element.uid.toString());
    element.width = obj.width;
    element.height = obj.height;
    element.time = obj.duration || 0;
    element.duration = safeTimeFormat(obj.duration || 0);
    element.btnTitle = "开始转换";
    element.btnTitleTwo = "视频剪切";
  });
};
const getFileName = (name: string) => {
  return name.substring(0, name.lastIndexOf("."));
};
const getExtension = (name: string) => {
  return name.substring(name.lastIndexOf(".") + 1);
};
const toConvert = (item: CustomUploadFile) => {
  if (item.btnTitle !== "开始转换") return;
  ffmpegRun(item, "btnTitle", "convert");
};
const showDialogVisible = (item: CustomUploadFile) => {
  currentItem.value = item;
  startTime.value = 0;
  endTime.value = item.time;
  dialogVisible.value = true;
};
const toCut = () => {
  const item = currentItem.value;
  dialogVisible.value = false;
  if (item) {
    if (item.btnTitleTwo !== "视频剪切") return;
    ffmpegRun(item, "btnTitleTwo", "cut");
  }
};
const ffmpegRun = (
  item: CustomUploadFile,
  k: "btnTitleTwo" | "btnTitle",
  type: string
) => {
  let ffmpegPath = `${path.join(process.cwd(), "/public/ffmpeg.exe")}`;

  /* 总的输入视频处理,开头需输入模板视频 */
  let videoInput = `-i "${item.raw?.path}"`;

  /* 输出配置及存储路径及文件名 */
  const savePath = path.join(
    store.config.savePath,
    `${new Date().getTime()}${getFFmpegSafeFilename(item.name)}`
  );

  // let str = `${ffmpegPath} ${videoInput} -vcodec h264 -s 1920*1080 -an -bf ${videobase} ${savePath}`;
  let str: string = "";
  if (type === "cut") {
    str = `${ffmpegPath} ${videoInput} -ss ${formatSecondsToTime(
      startTime.value || 0
    )} -t ${formatSecondsToTime(
      (endTime.value || 0) - startTime.value
    )} -c copy ${savePath}`;
  } else if (type === "convert") {
    str = `${ffmpegPath} ${videoInput} -c:v libx264 -crf 23 ${savePath}`;
  }
  let fpchild = exec(
    str,
    {
      encoding: "utf8",
      cwd: process.cwd(),
    },
    async (err: any, stdout: any, stderr: any) => {
      if (err) {
        console.error(err);
        return;
      }
    }
  ).on("exit", (code: any) => {
    console.log("子进程已退出, 退出码 " + code);
    if (code != 0) {
      ElMessage({
        message: `执行失败。请联系管理员`,
        type: "success",
        duration: 2000,
      });
    }
    item[k] = k === "btnTitleTwo" ? "视频剪切" : "开始转换";
  });
  fpchild.stdout.on("end", (code: any) => {
    ElMessage({
      message: `执行成功。文件路径${savePath}`,
      type: "success",
      duration: 4000,
    });
    item[k] = k === "btnTitleTwo" ? "视频剪切" : "开始转换";
  });
  fpchild.stderr.on("data", (data: any) => {
    const timeMatch = data.toString().match(/time=(\d+):(\d+):(\d+\.\d+)/);
    if (timeMatch) {
      const hours = parseInt(timeMatch[1]);
      const minutes = parseInt(timeMatch[2]);
      const seconds = parseFloat(timeMatch[3]);
      const currentTime = hours * 3600 + minutes * 60 + seconds;
      const progress = item?.time ? (currentTime / item?.time) * 100 : 0;
      item[k] = `${progress.toFixed(1)}%`;
    }
  });
};
const deleteItem = (index: number) => {
  fileList.value.splice(index, 1);
};
const getVideoInfo = async (id: string): Promise<VideoMetadata> => {
  const base = await getVideoMetadata(id);
  return {
    ...base,
  };
};
async function getVideoMetadata(id: string): Promise<VideoMetadata> {
  return new Promise((resolve, reject) => {
    nextTick(() => {
      const video = document.getElementById(id) as HTMLVideoElement;
      video.addEventListener("loadedmetadata", () => {
        resolve({
          width: video.videoWidth,
          height: video.videoHeight,
          duration: video.duration,
        });
      });

      // 错误处理
      video.addEventListener("error", (event) => {
        reject(
          new Error(`视频加载失败: ${event.error?.message || "未知错误"}`)
        );
      });
    });
  });
}
function safeTimeFormat(seconds: number) {
  // 处理非数字和负数
  if (isNaN(seconds) || seconds < 0) return "--:--:--";

  seconds = Math.floor(seconds);
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;

  return [h, m, s].map((unit) => String(unit).padStart(2, "0")).join(":");
}
function formatSecondsToTime(seconds: number) {
  // 确保 seconds 是整数
  seconds = Math.floor(seconds);

  // 计算小时、分钟和剩余秒数
  const hours = Math.floor(seconds / 3600);
  const remainingSeconds = seconds % 3600;
  const minutes = Math.floor(remainingSeconds / 60);
  const secs = remainingSeconds % 60;

  // 补零函数：将数字转换为两位数字符串（如 1 → "01"）
  const pad = (num: number) => String(num).padStart(2, "0");

  return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
}
/**
 * 生成 FFmpeg 兼容的安全文件名（自动处理空格、括号等特殊字符）
 * @param {string} filename - 原始文件名（可包含路径）
 * @returns {string} - 处理后的安全文件名
 */
function getFFmpegSafeFilename(filename: string) {
  // Step 1: 提取文件名和扩展名（保留最后一个点后的内容）
  const extIndex = filename.lastIndexOf(".");
  const name = extIndex > 0 ? filename.slice(0, extIndex) : filename;
  const ext = extIndex > 0 ? filename.slice(extIndex) : "";

  // Step 2: 替换所有非法字符（空格、括号、中文括号等）
  const safeName = name
    .replace(/[\s(){}[\]，,;:!@#$%^&+=]/g, "_") // 替换特殊符号为下划线
    .replace(/_+/g, "_") // 合并连续的下划线
    .replace(/^_+|_+$/g, ""); // 去除首尾的下划线

  // Step 3: 拼接处理后的名称和原扩展名
  return safeName + ext;
}
</script>

<style scoped lang="scss">
.main {
  background-color: #f2f3f5;
  margin-bottom: 5px;
  scroll-behavior: smooth;
  overscroll-behavior: contain;
  display: flex;
  justify-content: space-between;
}
.input-area {
  width: 100% !important;
  border-radius: 5px !important;
  height: calc(100vh - 100px);
  overflow-y: scroll;
}
.main-config-page {
  width: 100%;
  height: calc(100vh - 102px);
  background-color: #fff;
  border-radius: 5px;
  border: 1px solid #dcdfe6;
  overflow: hidden;
}
.table-tool {
  background-color: #fff;
  border-radius: 5px;
  border: 1px solid #dcdfe6;
  height: 68px;
  display: flex;
  justify-content: space-around;
  align-items: center;
}
.menu .el-menu {
  border: 1px solid #dcdfe6;
  border-radius: 5px;
  height: 30px;
}
.up-btn {
  margin: 16px 0;
}
.video-list {
  width: 100%;
  display: flex;
  padding: 10px;
  border: solid 2px #409eff;
  border-radius: 6px;
  box-sizing: border-box;
  gap: 10px;
  margin-bottom: 16px;
  align-items: center;
  justify-content: space-between;
  .video {
    width: 200px;
    height: auto;
    max-height: 112px;
  }
  .mid-content {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 1;
    .content {
      color: #000000;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: 100%;
      .row {
        display: flex;
        align-items: center;
        gap: 16px;
        & > span {
          display: flex;
          align-items: center;
          gap: 6px;
        }
      }
    }
  }

  .trans-box {
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
    gap: 10px;
    .trans-btn {
      margin-left: 0 !important;
      width: 88px;
    }
  }
  .delete-icon {
    cursor: pointer;
  }
}

:deep(.el-textarea__inner) {
  height: calc(100vh - 130px);
  resize: none;
  border-radius: 5px !important;
}
:deep(textarea::-webkit-scrollbar) {
  width: 5px;
}
:deep(textarea::-webkit-scrollbar-thumb) {
  width: 5px;
  position: relative;
  display: block;
  cursor: pointer;
  border-radius: inherit;
  background-color: rgb(183, 192, 201);
  transition: 0.3 background-color;
  opacity: 0.3;
}
:deep(.el-dialog) {
  --el-dialog-margin-top: 2vh;
}
:deep(.el-dialog__body img) {
  width: 100%;
}
</style>
